use std::pin::Pin;

// use actix_session::Session;
use actix_web::{
    App, HttpMessage, HttpServer, Responder,
    dev::{Service, ServiceRequest, Transform, forward_ready},
    get, web,
};
use chrono::format;
use futures_util::future::{Ready, ready};
use json::object;
use jsonwebtoken::{Algorithm, DecodingKey, Validation};
use auth::AuthClaims;
use serde::Serialize;

mod host;
mod auth;

#[derive(Default, Serialize)]
pub struct InfoResponse<T> {
    code: ResponseCode,
    message: String,
    data: Option<T>,
}

#[derive(Default, Serialize)]
enum ResponseCode {
    #[default]
    Success = 1,
    Failed = 0,
    Error = -1,
}

// #[derive(Debug)]
// pub enum MyError {
//     Unauthorized(String),
// }

// impl Display for MyError {
//     fn fmt(&self, f: &mut Formatter) -> FmtResult {
//         match self {
//             MyError::Unauthorized(s) => write!(f, "Unauthorized: {}", s),
//         }
//     }
// }

// impl std::error::Error for MyError {
//     fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
//         None
//     }
// }

// #[get("/")]
// async fn index(session: Session) -> impl Responder {
//     let session_id = uuid::Uuid::new_v4().to_string();
//     log::debug!("SESSION_ID={:?}", session_id);
//     session.insert("SESSION_ID", session_id).unwrap();
//     "Hello, World!"
// }

// #[get("/{name}")]
// async fn hello(name: web::Path<String>, session: Session) -> impl Responder {
//     // let key = actix_web::cookie::Key::generate();
//     log::debug!("SESSION_ID={:?}", session.get::<String>("SESSION_ID"));
//     format!("Hello {}!", &name)
// }

#[get("/{name}")]
async fn show(name: web::Path<String>) -> impl Responder {
    // let key = actix_web::cookie::Key::generate();
    // log::debug!("SESSION_ID={:?}", session.get::<String>("SESSION_ID"));
    format!("Hello {}!", &name)
}

#[get("/show/{name}")]
async fn user_detail(name: web::Path<String>) -> impl Responder {
    // let key = actix_web::cookie::Key::generate();
    // log::debug!("SESSION_ID={:?}", session.get::<String>("SESSION_ID"));
    format!("Hello {}!", &name)
}

// fn get_secret_key() -> Key {
//     // openssl rand -base64 64 | tr -d '\n'
//     let secret_key = include_str!("./key/cookie_secret_key.txt").as_bytes();
//     let key_bytes = BASE64_STANDARD.decode(secret_key).unwrap();
//     Key::from(&key_bytes)
// }

// 中间件定义
pub struct JwtAuthMiddleware;

impl<S> Transform<S, ServiceRequest> for JwtAuthMiddleware
where
    S: Service<
            ServiceRequest,
            Response = actix_web::dev::ServiceResponse,
            Error = actix_web::Error,
        > + 'static,
{
    type Response = actix_web::dev::ServiceResponse;
    type Error = actix_web::Error;
    type Transform = JwtAuthMiddlewareService<S>;
    type InitError = ();
    type Future = Ready<Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ready(Ok(JwtAuthMiddlewareService { service }))
    }
}

pub struct JwtAuthMiddlewareService<S> {
    service: S,
}

impl<S> Service<ServiceRequest> for JwtAuthMiddlewareService<S>
where
    S: Service<
            ServiceRequest,
            Response = actix_web::dev::ServiceResponse,
            Error = actix_web::Error,
        > + 'static,
{
    type Response = actix_web::dev::ServiceResponse;
    type Error = actix_web::Error;
    type Future = Pin<Box<dyn futures_util::Future<Output = Result<Self::Response, Self::Error>>>>;

    forward_ready!(service);
    // fn poll_ready(&self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
    //     self.service.poll_ready(cx)
    // }

    fn call(&self, req: ServiceRequest) -> Self::Future {
        let (status_code, message) = check_permission(&req);
        match status_code {
            200 => {
                let fut = self.service.call(req);
                Box::pin(async move {
                    let res = fut.await?;
                    Ok(res)
                })
            },
            _ => {
                let message = format!("{}: {}", status_code, message.unwrap());
                let data = object! {
                    code: "Error",
                    message: message,
                    data: null
                };
                // let data = InfoResponse {
                //     code: ResponseCode::Error,
                //     message,
                //     data: None
                // };
                
                let message = json::stringify(data);

                Box::pin(async move { 
                    match status_code {
                        400 => Err(actix_web::error::ErrorBadRequest(message)),
                        401 => Err(actix_web::error::ErrorUnauthorized(message)),
                        _ => Err(actix_web::error::ErrorForbidden(message)),
                    }
                })

            }
        }
    }
}

fn check_permission(req: &ServiceRequest) -> (u32, Option<String>) {
    // 排除无需验证的路径（如登录接口）
    if req.path().starts_with("/auth") {
        return (200, None);
    }

    // 从 Header 提取 Token
    let token = req
        .headers()
        .get(auth::TOKEN_CLIENT_KEY)
        .and_then(|h| h.to_str().ok())
        .and_then(|s| s.strip_prefix("Bearer "));

    let token = match token {
        Some(t) => t,
        None => return (400, Some("Missing Authorization Header".to_owned())),
    };

    // 验证 Token
    // let validation = Validation::new(Algorithm::RS256);
    // let pkcs8 = include_str!("./key/public_key.pem");
    // let secret_key = DecodingKey::from_rsa_pem(pkcs8.as_ref()).unwrap();
    let validation = Validation::default();
    let secret_key = include_str!("./key/access_token_secret_key.txt");
    let secret_key = DecodingKey::from_secret(secret_key.as_bytes());

    match jsonwebtoken::decode::<AuthClaims>(token, &secret_key, &validation) {
        Ok(token_data) => {
            req.extensions_mut().insert(token_data.claims);
            return (200, None);
        }
        Err(e) => {
            log::error!("{e}");
            let response = match e.kind() {
                jsonwebtoken::errors::ErrorKind::ExpiredSignature => "Token expired",
                _ => "Invalid Token",
            };
            return (401, Some(response.to_owned()));
        }
    }
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    // let der_file = match option_env!("AUTH_PRIVATE_KEY_FILE") {
    //     Some(file) => file,
    //     None => &format!("{:?}{}", std::env::current_dir().unwrap(), "/key/rsa-2048-private-key.pk8")
    // };
    // if let Err(e) = File::open(der_file) {
    //     eprintln!("{}: No such file, {e}", der_file);
    //     exit(1);
    // }
    log4rs::init_file("./log4rs.toml", Default::default()).unwrap();
    // let secret_key = get_secret_key();
    HttpServer::new(move || {
        App::new()
            // .wrap(
            //     SessionMiddleware::builder(CookieSessionStore::default(), secret_key.clone())
            //         .cookie_secure(false)
            //         .cookie_http_only(true)
            //         .build(),
            // )
            .wrap(JwtAuthMiddleware)
            // .default_service(
            //     web::route()
            //         .guard(actix_web::guard::Any(actix_web::guard::Get()).or(actix_web::guard::Post()))
            //         .to(HttpResponse::MethodNotAllowed),
            // )
            .service(
                web::scope("/auth")
                    .service(auth::auth_captcha)
                    .service(auth::auth_prelude)
                    .service(auth::auth)
                    .service(auth::refresh_access_token),
            )
            .service(web::scope("/host").service(host::list).service(host::add))
        // .service(web::scope("/guard").service(show).service(user_detail))
        // .service(login::auth)
        // .service(hello)
        // .service(
        //     web::resource("/auth").route(web::get().to(login::auth)))
        // .service(
        //     web::resource("/guard")
        //         .guard(guard::AuthGuard)
        //         .to(|| HttpResponse::Unauthorized())
        //         .route(route),
        // )
        // .service(
        //     web::scope("/guard").default_service(
        //         web::route()
        //             .guard(guard::AuthGuard)
        //             .to(HttpResponse::Unauthorized),
        //     ),
        // )
    })
    .bind(format!(":::65430"))?
    .run()
    .await
}
